﻿#region Imports
using System;
using System.Collections.Generic;
using System.Linq;
using CommonUtilities.Extensions;
using CommonUtilities.Properties;
#endregion

namespace CommonUtilities.Util
{
    /// <summary>
    /// Stores min-max pair for specified type <typeparamref name="TSource"/>
    /// </summary>
    /// <typeparam name="TSource">The type of the data to extract min-max pair for</typeparam>
    public class MinMaxPair<TSource> where TSource : struct
    {
        #region Properties
        /// <summary>
        /// Minimum value in pair
        /// </summary>
        public TSource? MinValue { get; private set; }

        /// <summary>
        /// Maximum value in pair
        /// </summary>
        public TSource? MaxValue { get; private set; }

        /// <summary>
        /// Incorrect values to skip evaluating min-max pair
        /// </summary>
        public TSource[] IncorrectValues { get; private set; }

        /// <summary>
        /// Specifies if any incorrect values was encountered
        /// </summary>
        public bool HasIncorrectValues { get; private set; }
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new default instance of the CommonUtilities.Util.MinMaxPair&lt;TSource&gt; class
        /// </summary>
        public MinMaxPair()
        {
            MaxValue = MinValue = null;
        }

        /// <summary>
        /// Initializes a new default instance of the CommonUtilities.Util.MinMaxPair&lt;TSource&gt; class
        /// to extract min/max values from a collection of values of type <typeparamref name="TSource"/>
        /// </summary>
        /// <param name="values">Collection of values of type <typeparamref name="TSource"/></param>
        /// <param name="incorrectValues">Incorrect values of type <typeparamref name="TSource"/></param>
        public MinMaxPair(IEnumerable<TSource> values, params TSource[] incorrectValues)
            : this()
        {
            IncorrectValues = incorrectValues;
            HasIncorrectValues = values._Where(val => incorrectValues._Contains(val))._Any() || values._None();

            IEnumerable<TSource> correctValues = values._Where(val => !incorrectValues._Contains(val));
            if (correctValues._Any())
            {
                MinValue = HasIncorrectValues ? correctValues._Min() : values._Min();
                MaxValue = HasIncorrectValues ? correctValues._Max() : values._Max();
            }
        }

        /// <summary>
        /// Initializes a new default instance of the CommonUtilities.Util.MinMaxPair&lt;TSource&gt; class
        /// to extract min/max values from a collection of min-max pairs of type <typeparamref name="TSource"/>
        /// </summary>
        /// <param name="pairs">Collection of min-max pairs of type <typeparamref name="TSource"/></param>
        public MinMaxPair(IEnumerable<MinMaxPair<TSource>> pairs)
            : this()
        {
            IncorrectValues = pairs.SelectMany(pr => pr.IncorrectValues).Distinct()._OrderBy(inc => inc).ToArray();
            HasIncorrectValues = pairs._Where(val => val.HasIncorrectValues)._Any() || pairs._None();

            IEnumerable<TSource?> correctValues = pairs._Select(pr => pr.MinValue)
                .Union(pairs._Select(pr => pr.MaxValue)).Distinct()._OrderBy(inc => inc);
            if (correctValues._Any())
            {
                MinValue = pairs._Select(pair => pair.MinValue)._Min();
                MaxValue = pairs._Select(pair => pair.MaxValue)._Max();
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Generates duration string for year values
        /// </summary>
        /// <param name="YearMinMaxPair">Min-max pair for years</param>
        /// <returns></returns>
        public static string GenerateDuration(MinMaxPair<int> YearMinMaxPair)
        {
            try
            {
                int? minValue = YearMinMaxPair.MinValue;
                int? maxValue = YearMinMaxPair.MaxValue;
                bool hasError = YearMinMaxPair.HasIncorrectValues;
                int[] incorrectValues = YearMinMaxPair.IncorrectValues;

                string result = "";

                if (minValue == maxValue) result = Convert.ToString(minValue);
                else result = "{0} - {1}".FormatTextFromParams(minValue, maxValue);

                return new string[] { hasError ? Resources.Const_NotAvailable : "", result }.AppendText(", ");
            }
            catch (Exception)
            {
                return Resources.Const_NotAvailable;
            }
        }
        #endregion Methods
    }
}
